﻿using filecopy.io.Item;
using filecopy.io.Path;
using SMBLibrary;
using SMBLibrary.Client;
using SMBLibrary.Server;
using System;
using FileAttributes = SMBLibrary.FileAttributes;

namespace filecopy.io.Container
{
    public class SmbContainer : IContainer
    {
        internal SMB2Client smb { get; set; }
        internal string path { get; set; } = string.Empty;
        internal string host { get; set; } = string.Empty;
        internal string user { get; set; } = string.Empty;
        internal string passwd { get; set; } = string.Empty;
        internal string sharename { get; set; } = string.Empty; //共享名称
        internal string nowpath { get; set; } = string.Empty;
        public SmbContainer()
        {
            this.smb = new SMB2Client();
        }

        public string NowPath => this.nowpath;
        public bool Login(string host, string username, string password)
        {
            bool isConnected = smb.Connect(host, SMBTransportType.DirectTCPTransport);
            if (isConnected)
            {
                var status = smb.Login(host, username, password);
                if (status == NTStatus.STATUS_SUCCESS)
                {
                    this.host = host;
                    this.user = user;
                    this.passwd = passwd;

                    return true;
                }
            }
            return false;
        }
        public IEnumerable<IFileCopyItem> FindItems(params string[] name_tags)
        {
            throw new NotImplementedException();
        }
        internal string[] fs_ls(ISMBFileStore fs, string path)
        {
            path = path.Replace("/", "\\");
            object directoryHandle;
            FileStatus fileStatus;
            var status = fs.CreateFile(out directoryHandle, out fileStatus, path, AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
            if (status == NTStatus.STATUS_SUCCESS)
            {
                status = fs.QueryDirectory(out var dirs, directoryHandle, "*", FileInformationClass.FileNamesInformation);

                if (dirs.Count > 0)
                {
                    var files = dirs.Cast<FileNamesInformation>().Where(t => t.FileName != "." && t.FileName != "..").Select(t => t.FileName);

                    return files.ToArray();
                }
            }
            return Array.Empty<string>();
        }
        /// <summary>
        /// 列出
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public string[] Ls()
        {
            var fs = smb.TreeConnect(this.sharename, out var status);
            if (status == NTStatus.STATUS_SUCCESS)
            {
                var files = fs_ls(fs, nowpath);

                fs.Disconnect();
                return files;
            }
            else throw new Exception($"访问出错， 访问目标{this.sharename}");
        }

        internal void fs_create_path(ISMBFileStore fs, string createpath)
        {
            var paths_stack = new Stack<string>(createpath.Split("/").Where(t => !string.IsNullOrWhiteSpace(t)));
            var pathname = paths_stack.Pop();
            var parentPath = string.Join("/", paths_stack.Reverse());
            var files = fs_ls(fs, parentPath);
            if (! files.Contains(pathname, StringComparer.OrdinalIgnoreCase))
            {
                if (paths_stack.Count != 0) fs_create_path(fs, parentPath);

                object fileHandle;
                FileStatus fileStatus2;
                var needadd_path = parentPath.Replace("/", "\\") + "\\" + pathname;
                if (paths_stack.Count == 0) needadd_path = pathname;
                var status = fs.CreateFile(out fileHandle, out fileStatus2, needadd_path, AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, FileAttributes.Directory, ShareAccess.None, CreateDisposition.FILE_CREATE, CreateOptions.FILE_DIRECTORY_FILE, null);
                if (status == NTStatus.STATUS_ACCESS_DENIED) throw new Exception("执行出错，没有创建目录的权限。");
            }
        }
        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <exception cref="Exception"></exception>
        public void CreatePath()
        {
            var fs = smb.TreeConnect(this.sharename, out var status);
            if (status == NTStatus.STATUS_SUCCESS)
            {
                fs_create_path(fs, nowpath);
                fs.Disconnect();
            }
            else throw new Exception($"访问出错， 访问目标{this.sharename}");
        }

        /// <summary>
        /// 转到
        /// </summary>
        /// <param name="path"></param>
        /// <exception cref="Exception"></exception>
        public void To(string path)
        {
            if (path.StartsWith("/")) this.path = path;
            else
            {
                path = System.IO.Path.Combine("t:\\" + this.path.Replace("/", "\\"), path.Replace("/", "\\"));
                this.path = path = System.IO.Path.GetFullPath(path).Replace("t:\\", "",StringComparison.OrdinalIgnoreCase).Replace("\\", "/");
            }
            var paths_q = new Queue<string>(this.path.Split("/").Where(t=> !string.IsNullOrWhiteSpace(t)));
            if (paths_q.Count == 0) throw new Exception("访问SMB时，信息不全(缺少共享名称)。");
            this.sharename = paths_q.Dequeue();

            if (paths_q.Count == 0) return;
            this.nowpath = string.Join("/", paths_q);
        }

        public void Dispose()
        {
            smb.Disconnect();
        }

        public IFileCopyPath TakeNowPath()
        {
            CreatePath();
            var item = new SmbPath(this);


            return item;
        }
    }
}
